class_name VelocityBasedRotation
extends Node
## 版本：1.0.0
## 功能：Node2D 节点基于移动速度的旋转
## 使用：将该脚本挂载到 Node 节点上，作为待旋转对象的子节点，配置 target 和其他导出变量。

#region Exported parameters
## 是否启用随速度旋转功能
@export var enabled: bool = true : set = _set_enabled

## 应用旋转的对象
@export var target: Node2D

## 旋转插值的时间，即完成一次旋转的时间
@export_range(0.25, 1.5) var lerp_seconds := 0.4

## 最大的旋转角度
@export var max_rotation_degrees := 30

## 开始旋转的门限速度
@export var x_velocity_threshold := 3.0
#endregion

#region Internal parameters
## 对象上一帧的位置，用于使用帧间隔位置来计算速度
var last_position: Vector2

## 对象的速度，用于判断对象速度是否达到门限速度
var velocity: Vector2

## 对象基于当前速度所需要旋转的角度
var angle: float

## 用于插值旋转角度
var progress: float

## 标识距离开始旋转的所用时间，用于计算 progress
var time_elapsed := 0.0
#endregion


# INFO: 使用 _physics_process 的原因
# 此处的旋转有一个门限速度，而判断是否到达门限速度是通过游戏运行的两帧之间的位置得到的
# 当游戏帧率越高，就越难达到门限速度
# 因此要么使用时间间隔来判断门限速度，要么就使用 _physics_process 来锁定 60 帧率
func _physics_process(delta: float) -> void:
	if not enabled or not target:
		return
	
	velocity = target.global_position - last_position
	last_position = target.global_position
	progress = time_elapsed / lerp_seconds
	
	if abs(velocity.x) > x_velocity_threshold:
		angle = velocity.normalized().x * deg_to_rad(max_rotation_degrees)
	else:
		angle = 0.0
	
	target.rotation = lerp_angle(target.rotation, angle, progress)
	time_elapsed += delta
	
	if progress > 1.0:
		time_elapsed = 0.0


func _set_enabled(value: bool) -> void:
	enabled = value
	
	if target and enabled == false:
		target.rotation = 0.0
